<?php declare(strict_types=1);

namespace App\Trait;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use Hyperf\Database\Model\Events\Saved;
use Hyperf\Database\Model\Events\Deleted;

/**
 * @property  $cacheKey 缓存 Key
 * @property  $orderField 排序字段
 * @property  $orderMethod 排序方法
 * @property  $cacheFields 要查询的字段
 * @property  $cacheTimeout 缓存有效时间
 */
trait ModelCacheTrait
{

    protected array $defaultValue = [
        'cacheFields' => '*',
        'orderField' => null,
        'orderMethod' => 'asc',
        'cacheTimeout' => 3600,
    ];

    public function saved(Saved $event)
    {
        $this->clearModelCache();
        try {
            parent::saved($event);
        } catch (\Throwable $t) {
        }
    }

    public function deleted(Deleted $event)
    {
        $this->clearModelCache();
        try {
            parent::deleted($event);
        } catch (\Throwable $t) {
        }
    }

    public static function getAllFromCache(bool $doSelect = true)
    {
        $static = new static();
        $redis = getRedis();
        $cacheKey = $static->property('cacheKey');
        if ($redis->exists($cacheKey)) {
            return json_decode($redis->get($cacheKey), true);
        }
        if (!$doSelect) return null;
        $query = static::query()->select($static->getCacheFields());
        if ($orderFiled = $static->getOrderField()) $query->orderBy($orderFiled, $static->getOrderMethod());
        $list = $query->orderBy('id')->get()->toArray();
        $redis->set($cacheKey, json_encode($list, JSON_UNESCAPED_UNICODE), $static->lifespan());
        return $list;
    }

    public function clearModelCache(): bool
    {
        if (method_exists($this, 'clearCache')) {
            $this->clearCache();
        }
        return (bool)getRedis()->del($this->property('cacheKey'));
    }

    public function property($key)
    {
        if (property_exists($this, $key)) {
            return $this->$key;
        }
        if (in_array($key, array_keys($this->defaultValue))) {
            return $this->defaultValue[$key];
        }
        throw new BusinessException(ErrorCode::ERR_SERVER);
    }

    /**
     * 获取缓存有效时间
     */
    public function lifespan(): int
    {
        $time = (int)$this->property('cacheTimeout');
        return $time - rand(10, 60);
    }

    public function getOrderField(): ?string
    {
        return $this->property('orderField');
    }

    public function getOrderMethod(): ?string
    {
        return $this->property('orderMethod');
    }

    public function getCacheFields(): ?array
    {
        return $this->property('cacheFields');
    }

}